##############################################################################
# SSH (Secure Shell) 速查表 (SSH Cheatsheet)
# 安全地连接到远程主机，执行命令，传输文件等。
# https://github.com/funnyzak/cli-cheatsheets
##############################################################################

# 图例 (Legend):
#   - USER:         远程主机的用户名 (Username on the remote host)
#   - HOST:         远程主机的地址 (Hostname or IP address of the remote host)
#   - PORT:         SSH 服务的端口号 (Port number for the SSH service, default: 22)
#   - COMMAND:      在远程主机上执行的命令 (Command to execute on the remote host)
#   - KEY_FILE:     私钥文件的路径 (Path to the private key file, e.g., ~/.ssh/id_rsa)
#   - LOCAL_PATH:   本地文件或目录路径 (Local file or directory path)
#   - REMOTE_PATH:  远程文件或目录路径 (Remote file or directory path)
#   - LOCAL_PORT:   本地端口号 (Local port number)
#   - REMOTE_PORT:  远程端口号 (Remote port number)
#   - TARGET_HOST:  目标主机名或 IP (通常用于端口转发) (Target hostname or IP, often for port forwarding)
#   - TARGET_PORT:  目标端口号 (通常用于端口转发) (Target port number, often for port forwarding)
#   - ALIAS:        在 ~/.ssh/config 中定义的主机别名 (Host alias defined in ~/.ssh/config)

##############################################################################
# 基本连接 (Basic Connection)
##############################################################################

ssh HOST                                      # 使用当前用户名连接到 HOST
ssh USER@HOST                                 # 使用指定用户名连接到 HOST
ssh USER@HOST -p PORT                         # 连接到指定端口
ssh HOST -l USER                              # 使用指定用户名连接 (另一种语法)
ssh ALIAS                                     # 使用 ~/.ssh/config 中定义的别名连接

##############################################################################
# 认证 (Authentication)
##############################################################################

ssh -i KEY_FILE USER@HOST                     # 使用指定的私钥文件进行认证
ssh -o PreferredAuthentications=password USER@HOST # 优先尝试密码认证
ssh -o PreferredAuthentications=publickey USER@HOST # 优先尝试公钥认证
ssh -o PubkeyAuthentication=no USER@HOST      # 禁用公钥认证 (强制密码)
ssh -o PasswordAuthentication=no USER@HOST    # 禁用密码认证 (强制公钥/其他)

##############################################################################
# 执行远程命令 (Executing Remote Commands)
##############################################################################

ssh USER@HOST COMMAND                         # 在远程主机上执行单个命令并退出
ssh USER@HOST 'COMMAND1; COMMAND2'            # 执行多个命令 (用引号包裹)
ssh USER@HOST "ls -l /var/log | grep mail"    # 执行带管道或重定向的命令

# 提示:
#   - 使用 -T 禁止分配伪终端 (适合脚本)
#   - 使用 -t 强制分配伪终端 (适合交互式程序如 top)

##############################################################################
# 文件传输 (File Transfer - 使用 scp/sftp)
# 注意: ssh 本身不直接传输文件，而是依赖 scp 或 sftp
##############################################################################

# SCP (Secure Copy Protocol)
scp LOCAL_PATH USER@HOST:REMOTE_PATH          # 从本地复制到远程
scp USER@HOST:REMOTE_PATH LOCAL_PATH          # 从远程复制到本地
scp -r LOCAL_PATH USER@HOST:REMOTE_PATH         # 递归复制目录
scp -P PORT LOCAL_PATH USER@HOST:REMOTE_PATH  # 指定远程主机的 SSH 端口 (注意是大写 P)
scp -i KEY_FILE LOCAL_PATH USER@HOST:REMOTE_PATH # 使用指定私钥

# SFTP (SSH File Transfer Protocol)
sftp USER@HOST                                # 启动交互式 SFTP 会话
# SFTP 内部常用命令: get, put, ls, cd, pwd, rm, mkdir, quit

##############################################################################
# 端口转发 / 隧道 (Port Forwarding / Tunneling)
##############################################################################

# 本地端口转发 (Local Port Forwarding)
# 将本地端口的连接转发到远程网络可访问的主机/端口
# Access remote service via local port
ssh -L LOCAL_PORT:TARGET_HOST:TARGET_PORT USER@HOST
# 示例: ssh -L 8080:localhost:80 user@remote -N # 本地访问 localhost:8080 即访问 remote 上的 localhost:80

# 远程端口转发 (Remote Port Forwarding)
# 将远程端口的连接转发到本地网络可访问的主机/端口
# Expose local service on remote host
ssh -R REMOTE_PORT:TARGET_HOST:TARGET_PORT USER@HOST
# 示例: ssh -R 9090:localhost:3000 user@remote -N # 远程访问 remote:9090 即访问本地的 localhost:3000

# 动态端口转发 (Dynamic Port Forwarding - SOCKS Proxy)
# 在本地创建一个 SOCKS 代理，流量通过 SSH 服务器转发
# Create a SOCKS proxy on local port forwarding through remote host
ssh -D LOCAL_PORT USER@HOST
# 示例: ssh -D 1080 user@remote -N # 配置浏览器/应用使用 SOCKS5 代理 localhost:1080

# 提示:
#   - 使用 -N 选项表示不执行远程命令，通常用于纯粹的端口转发。
#   - 使用 -f 选项使 ssh 在后台运行 (认证后)。

##############################################################################
# SSH Agent (管理私钥密码)
##############################################################################

eval $(ssh-agent -s)                          # 启动 ssh-agent (bash/zsh)
ssh-add                                       # 添加默认私钥 (~/.ssh/id_rsa, id_dsa, etc.)
ssh-add KEY_FILE                              # 添加指定的私钥
ssh-add -l                                    # 列出已添加的密钥
ssh-add -D                                    # 删除所有已添加的密钥
ssh -A USER@HOST                              # 启用 Agent Forwarding (将本地 agent 转发到远程)

# 提示: Agent Forwarding 有安全风险，仅在信任的远程主机上使用。

##############################################################################
# X11 转发 (X11 Forwarding)
##############################################################################

# 在本地显示远程主机的 GUI 程序窗口
# Display GUI applications from remote host locally
ssh -X USER@HOST                              # 启用 X11 转发 (受信任的)
ssh -Y USER@HOST                              # 启用受信任的 X11 转发 (安全性较低，但兼容性可能更好)

# 提示: 本地需要运行 X Server (如 XQuartz on macOS, Xming on Windows, or native X on Linux)

##############################################################################
# SSH 配置文件 (~/.ssh/config)
##############################################################################

# 简化连接命令，设置常用选项
# ~/.ssh/config 示例:
#
# Host my-server
#   HostName server.example.com
#   User myuser
#   Port 2222
#   IdentityFile ~/.ssh/my_server_key
#   ForwardAgent yes
#
# Host *.internal.example.com
#   User admin
#   ProxyJump bastion-host
#
# Host bastion-host
#   HostName bastion.example.com
#   User jumpuser

# 使用示例别名: ssh my-server

##############################################################################
# 密钥管理 (Key Management - ssh-keygen & ssh-copy-id)
##############################################################################

ssh-keygen                                    # 生成新的 SSH 密钥对 (交互式)
ssh-keygen -t rsa -b 4096                     # 生成 4096 位的 RSA 密钥对
ssh-keygen -t ed25519                         # 生成 Ed25519 密钥对 (推荐，更现代安全)
ssh-keygen -f ~/.ssh/custom_key -t ed25519    # 指定生成的文件名
ssh-keygen -p -f KEY_FILE                     # 修改私钥的密码
ssh-keygen -y -f KEY_FILE > public_key.pub    # 从私钥导出公钥

ssh-copy-id USER@HOST                         # 将默认公钥 (~/.ssh/id_*.pub) 追加到远程主机的 authorized_keys
ssh-copy-id -i ~/.ssh/mykey.pub USER@HOST     # 指定要复制的公钥文件
ssh-copy-id -p PORT USER@HOST                 # 指定远程主机的 SSH 端口

##############################################################################
# 调试和详细输出 (Debugging and Verbosity)
##############################################################################

ssh -v USER@HOST                              # 详细模式 (显示调试信息)
ssh -vv USER@HOST                             # 更详细模式
ssh -vvv USER@HOST                            # 最详细模式 (用于深度调试)

##############################################################################
# 实用技巧 (Tips and Tricks)
##############################################################################

# 保持连接活动 (防止超时断开)
# 在 ~/.ssh/config 中添加:
# Host *
#   ServerAliveInterval 60
#   ServerAliveCountMax 3
# 或命令行: ssh -o ServerAliveInterval=60 USER@HOST

# 使用 ControlMaster 加速重复连接
# 在 ~/.ssh/config 中添加:
# Host *
#  ControlMaster auto
#  ControlPath ~/.ssh/cm-%r@%h:%p
#  ControlPersist 10m
# 第一次连接会创建 socket，后续连接复用，速度极快。

# 跳板机/堡垒机连接 (Jump Host)
ssh -J USER_JUMP@HOST_JUMP USER@HOST_TARGET   # 通过 HOST_JUMP 连接到 HOST_TARGET
# 或在 ~/.ssh/config 中配置 ProxyJump

# 检查 SSH 服务器公钥指纹
ssh-keyscan HOST                              # 获取主机的公钥
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub  # 查看本地服务器的指纹

##############################################################################
# 示例 (Examples)
##############################################################################

# 1. 使用特定用户和端口连接，并执行 ls
#   ssh alice@example.com -p 2222 'ls -l /home/alice'

# 2. 使用密钥文件连接，并将本地 8080 端口转发到远程服务器的 3000 端口
#   ssh -i ~/.ssh/my_key bob@remote.server -N -L 8080:localhost:3000

# 3. 使用 ssh-copy-id 安装公钥
#   ssh-copy-id -i ~/.ssh/id_ed25519.pub charlie@new-machine

# 4. 通过跳板机连接到内部服务器 (使用 config)
# ~/.ssh/config:
#   Host internal-db
#     HostName 10.0.1.50
#     User dbadmin
#     ProxyJump bastion
#   Host bastion
#     HostName bastion.example.com
#     User ops
# 命令行: ssh internal-db

##############################################################################
# 鸣谢 & 更多资源 (Credit & Further Resources)
##############################################################################

# man ssh
# man ssh_config
# man sshd_config
# man ssh-keygen
# man ssh-agent
# man ssh-add
# man scp
# man sftp
# https://www.ssh.com/ssh/
# https://github.com/funnyzak/cli-cheatsheets

# vim: set ts=4 sw=4 tw=0 et ft=bash :
